a3e622
@@ -21,11 +21,12 @@
import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.springframework.lang.Nullable;
 import org.springframework.util.Assert;
 import org.springframework.util.ObjectUtils;
-import org.springframework.util.StringUtils;
 
 import static java.nio.charset.StandardCharsets.*;
 import static java.time.format.DateTimeFormatter.*;
@@ -253,9 +254,8 @@
public class ContentDisposition {
 	 * @see #toString()
 	 */
 	public static ContentDisposition parse(String contentDisposition) {
-		String[] parts = StringUtils.tokenizeToStringArray(contentDisposition, ";");
-		Assert.isTrue(parts.length >= 1, "Content-Disposition header must not be empty");
-		String type = parts[0];
+		List<String> parts = tokenize(contentDisposition);
+		String type = parts.get(0);
 		String name = null;
 		String filename = null;
 		Charset charset = null;
@@ -263,8 +263,8 @@
public class ContentDisposition {
 		ZonedDateTime creationDate = null;
 		ZonedDateTime modificationDate = null;
 		ZonedDateTime readDate = null;
-		for (int i = 1; i < parts.length; i++) {
-			String part = parts[i];
+		for (int i = 1; i < parts.size(); i++) {
+			String part = parts.get(i);
 			int eqIndex = part.indexOf('=');
 			if (eqIndex != -1) {
 				String attribute = part.substring(0, eqIndex);
@@ -318,6 +318,41 @@
public class ContentDisposition {
 		return new ContentDisposition(type, name, filename, charset, size, creationDate, modificationDate, readDate);
 	}
 
+	private static List<String> tokenize(String headerValue) {
+		int index = headerValue.indexOf(';');
+		String type = (index >= 0 ? headerValue.substring(0, index) : headerValue).trim();
+		if (type.isEmpty()) {
+			throw new IllegalArgumentException("Content-Disposition header must not be empty");
+		}
+		List<String> parts = new ArrayList<>();
+		parts.add(type);
+		if (index >= 0) {
+			do {
+				int nextIndex = index + 1;
+				boolean quoted = false;
+				while (nextIndex < headerValue.length()) {
+					char ch = headerValue.charAt(nextIndex);
+					if (ch == ';') {
+						if (!quoted) {
+							break;
+						}
+					}
+					else if (ch == '"') {
+						quoted = !quoted;
+					}
+					nextIndex++;
+				}
+				String part = headerValue.substring(index + 1, nextIndex).trim();
+				if (!part.isEmpty()) {
+					parts.add(part);
+				}
+				index = nextIndex;
+			}
+			while (index < headerValue.length());
+		}
+		return parts;
+	}
+
 	/**
 	 * Decode the given header field param as describe in RFC 5987.
 	 * <p>Only the US-ASCII, UTF-8 and ISO-8859-1 charsets are supported.
